﻿#include "remoteobject_p.h"
#include "remoteobject.h"
#include "metaproperty.h"
#include "dynamicremoteobject.h"
#include "remoteobjectnode.h"
#include "metasignal.h"
#include "metafunction.h"

RemoteObjectNodeBase::RemoteObjectNodeBase(RemoteObjectNodeBasePrivate *p):_P(p)
{
    _P->isActive = false;
    _P->channel.NewMessage.Bind([=](){slotOnMessage();},this);
}

RemoteObjectNodeBase::~RemoteObjectNodeBase()
{

}

bool RemoteObjectNodeBase::isActive() const
{
    return _P->isActive;
}

void RemoteObjectNodeBase::OnMessage(Message* message)
{

}

void RemoteObjectNodeBase::SendMessage(Message *message)
{
    _P->channel.SendMessage(message);
}

void RemoteObjectNodeBase::SendMessage(Message *message, ClientId id)
{
    _P->channel.SendMessage(message,id);
}

void RemoteObjectNodeBase::UnRegister(RemoteObject *obj)
{

}

void RemoteObjectNodeBase::slotOnMessage()
{
    while (_P->channel.hasMessage()) {
        MessagePtr message = _P->channel.nextMessage();
        OnMessage(message.get());
    }
}

RemoteObjectNode::RemoteObjectNode(RemoteObjectNodePrivate *P):RemoteObjectNodeBase(new RemoteObjectNodePrivate)
{

}

RemoteObjectNode::RemoteObjectNode():RemoteObjectNode(new RemoteObjectNodePrivate)
{

}

RemoteObjectNode::~RemoteObjectNode()
{

}

void RemoteObjectNode::connectTo(std::string hostName)
{
    if(_d()->isActive){
        return;
    }

    int pos = hostName.find(":");

    std::string ip(hostName.begin(),hostName.begin() + pos);
    int port = std::atoi(std::string(hostName.begin()+pos + 1,hostName.end()).c_str());

    _P->channel.ConnectTo(ip,port);
    _d()->isActive = true;

	RequestObject m;
	SendMessage(&m);
}

void RemoteObjectNode::SetClassFactory(ClassFactory factory)
{
	_d()->factory = factory;
}

RemoteObject * RemoteObjectNode::Acquire(std::string shareName)
{
	if (_d()->objectList.count(shareName)) {
		std::string className = _d()->objectList[shareName];
		auto info = _d()->factory.FindClass(className.c_str());
		if (info.IsValid()) {
			return Acquire(shareName.c_str(), info);
		}
	}
	return nullptr;
}

RemoteObject *RemoteObjectNode::Acquire(const char *shareName,MetaInfo meta)
{
    if(!_d()->isActive){
        return NULL;
    }

    if(_d()->pool.count(shareName)){
        RemoteObjectData &data = _d()->pool[shareName];
        if(data.obj->GetMetaInfo() == meta)
        {
            return data.obj;
        }
        else{
        return NULL;
        }
    }
    else
    {
        RemoteObject* obj = meta.MetaCast<RemoteObject>(meta.Create());
        RemoteObject::PrivateCreate P;
        P.node = this;
        P.role = RemoteObject::Role::R_Replica;
        P.status = RemoteObject::Status::S_Uninited;
        obj->PrivateInit(P);
        RemoteObjectData data;
        data.phase = RemoteObjectData::InitializingProperty;
        data.obj = obj;
        data.shareName = shareName;
        _d()->pool[shareName] = data;

        RequestObject req;

        req.shareName = shareName;

        SendMessage(&req);//向服务端发送远程对象获取请求
        return obj;
    }

    return NULL;
}

DynamicRemoteObject *RemoteObjectNode::AcquireDynamic(const char *shareName)
{
    if(!_d()->isActive){
        return NULL;
    }

    if(_d()->pool.count(shareName)){
        RemoteObjectData &data = _d()->pool[shareName];
        return dynamic_cast<DynamicRemoteObject*>(data.obj);
    }
    else{
        auto meta = DynamicRemoteObject::staticMetaInfo();
        DynamicRemoteObject* obj = static_cast<DynamicRemoteObject*>(meta.Create());
        RemoteObject::PrivateCreate P;
        P.node = this;
        P.role = RemoteObject::Role::R_Replica;
        P.status = RemoteObject::Status::S_Uninited;
        obj->PrivateInit(P);

        RemoteObjectData data;
        data.phase = RemoteObjectData::InitializingMeta;//动态RO需要先从服务器获取该对象的元信息
        data.obj = obj;
        data.shareName = shareName;
        _d()->pool[shareName] = data;

        RequestObjectMeta req;

        req.shareName = shareName;

        SendMessage(&req);//向服务端发送远程对象获取请求
        return obj;
    }
}

void RemoteObjectNode::OnMessage(Message* message)
{
	if (message->type == RO_ReplyObjectList) {
		auto rep = dynamic_cast<ReplyObjectList*>(message);
		_d()->objectList = rep->objs;
	}
    else if(message->type == RO_ReplyObject){
        auto rep = dynamic_cast<ReplyObject*>(message);

        if(_d()->pool.count(rep->shareName))
        {
            auto & data = _d()->pool[rep->shareName];
            data.phase = RemoteObjectData::Initialized;
            MetaInfo meta = data.obj->GetMetaInfo();
            RemoteObject* obj = data.obj;
            void* v = dynamic_cast<void*>(obj);
            for(auto i:rep->propertys)
            {
				auto value = i.second;
				auto prop = meta.GetProperty(i.first);
				InputValueFix(value, prop.Type());
				obj->UpdateValue(i.first,value);
            }

            RemoteObject::PrivateCreate P;
            P.node = this;
            P.role = RemoteObject::Role::R_Replica;
            P.status = RemoteObject::Status::S_Normal;
            obj->PrivateInit(P);

            obj->Initialized();
        }
    }
	else if (message->type == RO_NewObject) {
		auto rep = dynamic_cast<NewObject*>(message);
		_d()->objectList[rep->shareName] = rep->className;
		newObject(rep->shareName, rep->className);
	}
    else if(message->type == RO_ReplyObjectMeta)
    {
        auto rep = dynamic_cast<ReplyObjectMeta*>(message);
        if(_d()->pool.count(rep->shareName))
        {
            auto & data = _d()->pool[rep->shareName];
            data.phase = RemoteObjectData::InitializingProperty;

            //重定向元对象

            DynamicRemoteObject* obj = dynamic_cast<DynamicRemoteObject*>(data.obj);

			obj->Redirect(rep->meta);

            auto meta = obj->GetMetaInfo();

            RequestObject req;

            req.shareName = rep->shareName;

            SendMessage(&req);//向服务端发送远程对象获取请求
        }
    }
    else if(message->type == RO_ObjectClosed){
        auto rep = dynamic_cast<ObjectClosed*>(message);
		_d()->objectList.erase(rep->shareName);
    }
    else if(message->type == RO_PropertyUpdate){
        auto rep = dynamic_cast<PropertyUpdate*>(message);
        if(_d()->pool.count(rep->shareName))
        {
            auto & data = _d()->pool[rep->shareName];
            MetaInfo meta = data.obj->GetMetaInfo();
            RemoteObject* obj = data.obj;
			Variant value = rep->value;
			auto prop = meta.GetProperty(rep->propertyId);
			InputValueFix(value, prop.Type());
			obj->UpdateValue(rep->propertyId, value);
        }
    }
    else if(message->type == RO_SignalInvoked){
        auto rep = dynamic_cast<SignalInvoked*>(message);
        if(_d()->pool.count(rep->shareName))
        {
            auto & data = _d()->pool[rep->shareName];
            MetaInfo meta = data.obj->GetMetaInfo();
            RemoteObject* obj = data.obj;
            GenericSignal* signal = meta.GetSignal(rep->index).GetSignal(dynamic_cast<void*>(obj));

			signal->DynamicInvoke(rep->args);
        }
    }
    else if(message->type == RO_SlotFinished){
        auto rep = dynamic_cast<SlotFinished*>(message);
        if(_d()->Requests.count(rep->ReplyId)){
            FunctionRequestData& data = _d()->Requests[rep->ReplyId];
            data.future->FinishWork(rep->ret);
			int i = rep->ret.Value<int>();
            _d()->Requests.erase(rep->ReplyId);
        }
    }
}

void RemoteObjectNode::UnRegister(RemoteObject *obj)
{
    auto data = findObject(obj);
    if(!data){
        return;
    }

    UnRegisterObject m;

    m.shareName = data->shareName;

    SendMessage(&m);

    _d()->pool.erase(m.shareName);
}

RemoteObjectData *RemoteObjectNode::findObject(RemoteObject *obj)
{
    for(auto& i:_d()->pool){
        if(i.second.obj == obj){
            return &i.second;
        }
    }

    return NULL;
}

void RemoteObjectNode::pushProperty(RemoteObject *obj, int idx,const Variant& param)
{
    auto data = findObject(obj);
    if(!data){
        return;
    }

	auto value = param;

	bool ok = OutputValueFix(value);

	if (!ok) {
		return;
	}

    PropertyPush m;

    m.shareName = data->shareName;
    m.idx = idx;
    m.value = value;
	

    SendMessage(&m);
}

std::shared_ptr<WorkFuture<Variant>> RemoteObjectNode::invokeFunction(RemoteObject *obj, int idx,const VariantList& param, bool sync)
{
    std::shared_ptr<WorkFuture<Variant>> ret = std::make_shared<WorkFuture<Variant>>();

    auto data = findObject(obj);
    if(!data){
        std::shared_ptr<WorkFuture<Variant>> ret;
    }

    SlotRequest m;

    m.shareName = data->shareName;
    m.funIdx = idx;
    m.response = sync;

    if(sync){
        ret->AddWork();
        FunctionRequestData req;
        req.future = ret;
        req.RequestId = _d()->maxRequest++;
        _d()->Requests[req.RequestId] = req;
		m.RequestId = req.RequestId;
    }
    else{
        m.RequestId = 0;
    }

    m.arguments = param;

    SendMessage(&m);
    return ret;
}

void RemoteObjectNode::InputValueFix(Variant & v, MetaTypeId targetId)
{
	MetaType meta = targetId;

	if (meta.isPointerToReflectable()) {
		std::string shareName = v.Value<std::string>();

		RemoteObject* obj = Acquire(shareName);

		v = Variant::FromValue(obj);
		v.Convert(targetId);
	}
}

bool RemoteObjectNode::OutputValueFix(Variant & v)
{
	MetaType meta = v.TypeId();
	if (meta.isPointerToReflectable()) {
		RemoteObject* obj = dynamic_cast<RemoteObject*>(v.Value<Reflectable*>());
		auto data = findObject(obj);
		if (!data) {
			std::cerr << "Error! Can't Find RemoteObject In Node" << std::endl;
			return false;
		}
		v = Variant::FromValue(data->shareName);
	}

	return true;
}

RemoteObjectNodePrivate *RemoteObjectNode::_d()
{
    return static_cast<RemoteObjectNodePrivate *>(_P.get());
}

void RemoteObjectNode::close() {

}